﻿/*
 * Copyright 2005-2011 Edward L. Stauff.                  Contact: <EdStauff@gmail.com>.
 * 
 * This file, "XmlUtils.cs", is part of the "Stauffware.Xml" library.
 * "Stauffware.Xml" is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by the 
 * Free Software Foundation, either version 3 of the License, or (at your 
 * option) any later version.
 * 
 * "Stauffware.Xml" is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser Public License along  
 * with "Stauffware.Xml".  If not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.Globalization;
using System.IO;
using Stauffware.Common.Core;

namespace Stauffware.Common.Xml
{
	/// <summary>
	/// Contains static XML utility methods.
	/// </summary>
	public static class XmlUtils
	{
		//-----------------------------------------------------------------------------
		/// <summary>
		/// Returns an XmlErrorReporter that writes each error to the given TextWriter.
		/// </summary>

		public static XmlErrorReporter ErrorReporter (TextWriter tw)
		{
			return delegate (XmlError e) { tw.WriteLine(e.ToString()); return true; };
		}

		//-----------------------------------------------------------------------------
		/// <summary>
		/// Checks to see if the given name is a valid XML element or attribute name.
		/// Returns an error message, or null on success.
		/// </summary>
		/// <remarks>Unlike System.Xml.XmlReader.IsName, this method tells you why.</remarks>

		public static string ValidateXmlName (string name)
		{
			Require.NotNull(name);
			if (name == "")
				return "a name cannot be empty";

			bool initial = true;
			foreach (char c in name)
			{
				if (!IsValidNameChar(c, initial))
					return "invalid character: '" + c + "' (0x" + ((int) c).ToString("X") + ")";
				initial = false;
			}

			return null;
		}

		//-----------------------------------------------------------------------------

		private static bool IsValidNameChar (char c, bool initial)
		{
			if (char.IsLetter(c)) return true;
			if (c == '_' || c == ':') return true;
			if (initial) return false;
			if (char.IsDigit(c)) return true;
			if (c == '.' || c == '-') return true;

			// TO-DO: add checks for Unicode "combining characters" and 
			//		  "extender characters", which are also valid per the official XML spec.

			return false;
		}

		//-----------------------------------------------------------------------------
		/// <summary>
		/// Reads all the nodes from the given reader and writes a text reprentation
		/// of the nodes to the given TextWriter.
		/// This is intended only for debugging.
		/// </summary>

		public static void DumpNodes (XmlReader rdr, TextWriter wtr)
		{
			while (rdr.Read())
				wtr.WriteLine(NodeToText(rdr));
		}

		//-----------------------------------------------------------------------------
		/// <summary>
		/// Returns a text representation of the current node in the given reader.
		/// This is intended only for debugging.
		/// </summary>

		public static string NodeToText (XmlReader rdr)
		{
			string str = rdr.NodeType.ToString();
			if (!string.IsNullOrEmpty(rdr.Name))
				str += " \"" + rdr.Name + "\"";
			if (!string.IsNullOrEmpty(rdr.Value))
				str += " = " + CharEncoding.ToCsharpLiteral(rdr.Value);

			//switch (rdr.NodeType)
			//{
			//    case XmlNodeType.Attribute:
			//        str += " = \"" + rdr.Value + "\"";
			//}
			return str;
		}

		//-----------------------------------------------------------------------------
		/// <summary>
		/// Returns a text representation of the given node.
		/// This is intended only for debugging.
		/// </summary>

		public static string NodeToText (XmlNode node)
		{
			if (node == null)
				return "NULL";
			string str = node.NodeType.ToString();
			if (!string.IsNullOrEmpty(node.Name))
				str += " \"" + node.Name + "\"";
			if (!string.IsNullOrEmpty(node.Value))
				str += " = " + CharEncoding.ToCsharpLiteral(node.Value);

			//switch (rdr.NodeType)
			//{
			//    case XmlNodeType.Attribute:
			//        str += " = \"" + rdr.Value + "\"";
			//}
			return str;
		}

		//-----------------------------------------------------------------------------
	}
}
